package com.threeox.commonlibrary.callback;

import android.os.Message;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.threeox.commonlibrary.config.CommonConfig;
import com.threeox.commonlibrary.entity.engine.request.network.ResponseConfigMsg;
import com.threeox.commonlibrary.inter.IOverallConfig;
import com.threeox.commonlibrary.inter.OnHttpListener;
import com.threeox.commonlibrary.util.CommonConstant;
import com.threeox.commonlibrary.util.JSONUtils;
import com.threeox.commonlibrary.util.ValueUtils;
import com.threeox.httplibrary.callback.StringCallback;
import com.threeox.utillibrary.util.EmptyUtils;
import com.threeox.utillibrary.util.HandlerUtils;
import com.threeox.utillibrary.util.HandlerUtils.OnHandlerListener;
import com.threeox.utillibrary.util.LogUtils;
import com.threeox.utillibrary.util.RegexUtils;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Matcher;

import okhttp3.Call;

/**
 *
 * @ClassName: CommonCallback
 *
 * @Description: Todo(赵屈犇)
 *
 * @author 赵屈犇
 *
 * @date 创建时间:2016/12/21 15:23
 *
 * @version 1.0
 */
public class CommonCallback<T> extends StringCallback implements OnHandlerListener {

    private final String TAG = CommonCallback.class.getName();

    private String msgKey;
    private HandlerUtils mHandler;
    private Class resultClass;// 结果数据的Class,默认是JSONObject
    private Class responseClass; // 响应结果数据的Class,默认是JSONObject
    private ResponseConfigMsg respConfigMsg; //响应数据解析对象配置
    private Map<String, Object> replaceParam;// 代替的参数

    private OnHttpListener onHttpListener;

    public static final String NOTDATAERRORCODE = UUID.randomUUID().toString();
    public static final String EXCEPTIONERRORCODE = UUID.randomUUID().toString();
    // 请求成功 和失败
    private final int SUCCESS = 0, ERROR = 1;

    private CommonConfig mCommonConfig;
    private IOverallConfig mOverallConfig;

    public CommonCallback() {
        this.mCommonConfig = CommonConfig.getInstance();
        this.mOverallConfig = mCommonConfig.getOverallExtend();
        this.mHandler = HandlerUtils.getInstance().setOnHandlerListener(this);
    }

    @Override
    public void onError(Call call, Exception e, int id, String url) {
        CallBackMsg callbackMsg = new CallBackMsg(id, url, e.getLocalizedMessage(), null);
        callbackMsg.setErrorCode(EXCEPTIONERRORCODE);
        errorData(callbackMsg);
        // onError(url, id, EXCEPTIONERRORCODE, e.getMessage());
    }

    @Override
    public void onResponse(final String response, final int id, final String url) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                onSuccess(response, id, url);
            }
        }).start();
    }

    public void onSuccess(String msg, int id ,String url) {
        try {
            if (mOverallConfig != null) {
                Object result = mOverallConfig.onBeforeResponse(url, id, msg);
                if (result != null) {
                    msg = String.valueOf(result);
                }
                boolean isIntercept = mOverallConfig.onInterceptRequestSuccess(msg, id, url, this);
                if (isIntercept) {
                    return;
                }
            }
            if (responseClass != null) {
                Object result = JSON.parseObject(msg, responseClass);
                if (result instanceof Collection) {
                    successData(url, id, msg, result, result);
                    // mHandler.put(new CallBackMsg(id, url, msg, result)).putWhat(SUCCESS).send();
                } else {
                    parse(msg, id, url, result);
                }
            } else {
                parse(msg, id, url, null);
            }
        } catch (Exception e) {
            LogUtils.e(TAG, e.getMessage() + "请求失败:" + msg);
            CallBackMsg callbackMsg = new CallBackMsg(id, url, e.getLocalizedMessage(), null);
            callbackMsg.setErrorCode(EXCEPTIONERRORCODE);
            errorData(callbackMsg);
            // mHandler.put(callbackMsg).putWhat(ERROR).send();
        }
    }

    /**
     * 解析
     *
     * @param msg
     * @param id
     * @param url
     */
    private void parse(String msg, int id, String url, Object oldResult) {
        JSONObject data = JSON.parseObject(msg);
        if (parseByRespConfig(data, id, url)){
            if (EmptyUtils.isNotEmpty(msgKey)) {
                parseByMsgKey(data, id, url);
            } else {
                successData(url, id, msg, data, oldResult);
                // mHandler.put(new CallBackMsg(id, url, msg, data)).putWhat(SUCCESS).send();
            }
        }
    }

    /**
     * 解析数据根据 响应对象的配置信息
     *
     * @param data
     * @param id
     * @param url
     *
     * @return
     */
    private boolean parseByRespConfig(JSONObject data, int id, String url) {
        try {
            if (respConfigMsg != null && data != null) {
                String codeName = respConfigMsg.getCodeName();
                String dataName = respConfigMsg.getDataName();
                String msgName = respConfigMsg.getMsgName();
                String succeedCode = respConfigMsg.getSucceedCode();
                Object codeValue = data.get(codeName);
                if (succeedCode.equals(String.valueOf(codeValue))) {
                    if (EmptyUtils.isNotEmpty(msgKey)) {
                        parseByMsgKey(data, id, url);
                    } else {
                        Object result = JSONUtils.getJSONValue(data, dataName);
                        success(data.getString(msgName), String.valueOf(result), id, url, data);
                        /*if (EmptyUtils.isNotEmpty(result)) {
                        } else {
                            CallBackMsg callbackMsg = new CallBackMsg(id, url, "没有请求到数据...", null);
                            callbackMsg.setErrorCode(NOTDATAERRORCODE);
                            errorData(callbackMsg);
                            // mHandler.put(callbackMsg).putWhat(ERROR).send();
                        }*/
                    }
                } else {
                    Object result = JSONUtils.getJSONValue(data, dataName);
                    CallBackMsg callbackMsg = new CallBackMsg(id, url, data.getString(msgName), result);
                    callbackMsg.setErrorCode(codeValue);
                    errorData(callbackMsg);
                    // mHandler.put(callbackMsg).putWhat(ERROR).send();
                }
                return false;
            }
        } catch (Exception e) {
        }
        return true;
    }


    /**
     * 解析数据根据MsgKeys
     *
     * @param data
     */
    private void parseByMsgKey(JSONObject data, int id ,String url) {
        try {
            Object val = JSONUtils.getJSONValue(data, msgKey);
            if (val != null) {
                success(val.toString(), val.toString(), id, url, data);
            } else {
                CallBackMsg callbackMsg = new CallBackMsg(id, url, "没有请求到数据...", null);
                callbackMsg.setErrorCode(NOTDATAERRORCODE);
                errorData(callbackMsg);
                // mHandler.put(callbackMsg).putWhat(ERROR).send();
            }
        } catch (Exception e) {
            CallBackMsg callbackMsg = new CallBackMsg(id, url, e.getLocalizedMessage(), null);
            callbackMsg.setErrorCode(EXCEPTIONERRORCODE);
            errorData(callbackMsg);
            // mHandler.put(callbackMsg).putWhat(ERROR).send();
        }
    }

    /**
     * 成功返回对象
     *
     * @param msg
     * @param result
     * @param id
     * @param url
     * @param oldResult 没有处理过得结果
     */
    private void success(String msg, String result, int id ,String url, Object oldResult) {
        Class<T> clazz = null;
        if (EmptyUtils.isNotEmpty(resultClass)){
            clazz = this.resultClass;
        } else {
            Type type = getClass().getGenericSuperclass();
            if (EmptyUtils.isNotEmpty(type) && type instanceof ParameterizedType
                    && EmptyUtils.isNotEmpty(((ParameterizedType) type).getActualTypeArguments())){
                clazz = (Class<T>) ((ParameterizedType) type).getActualTypeArguments()[0];
            }
        }
        if (EmptyUtils.isNotEmpty(clazz)) {
            try {
                Object data = JSON.parseObject(result, clazz);
                replaceData(data);//替换参数
                successData(url, id, msg, data, oldResult);// 如果是对象就返回对象
            } catch (Exception e) {
                LogUtils.e(getClass(), e.getLocalizedMessage());
                try {
                    // 解析为集合
                    List list = JSON.parseArray(result, clazz);
                    replaceData(list);
                    successData(url, id, msg, list, oldResult);
                } catch (Exception e1) {// 不是集合也不是对象
                    LogUtils.e(TAG, e1.getLocalizedMessage());
                    successData(url, id, msg, result, oldResult);
                }
            }
        } else {
            try {
                successData(url, id, msg, JSONObject.parse(msg), oldResult);
            } catch (Exception e) {
                LogUtils.e(TAG, e.getLocalizedMessage());
                successData(url, id, msg, result, oldResult);
            }
        }
    }

    /**
     * 替换返回的数据
     *
     * @param datas
     */
    private void replaceData(List datas) {
        if (EmptyUtils.isNotEmpty(datas)) {
            for (Object data : datas) {
                replaceData(data);
            }
        }
    }

    /**
     * 替换数据
     *
     * @param data
     */
    public void replaceData(Object data){
        if (EmptyUtils.isEmpty(replaceParam)) {
            return;
        }
        Set<String> set = replaceParam.keySet();
        for (String key : set) {
            Object val = ValueUtils.getObjValue(data, key);
            if (EmptyUtils.isNotEmpty(val)) {
                Matcher matcher = RegexUtils.getMatche(CommonConstant.RegularExp.EL_REG, String.valueOf(replaceParam.get(key)));
                while (matcher.find()) {
                    String group = matcher.group(1);
                    if (data != null) {
                        if (("${" + group + "}").equals(val)) {
                        } else {
                            val = String.valueOf(replaceParam.get(key)).replace("${" + group + "}", String.valueOf(val));
                        }
                    } else {
                        LogUtils.e("替换${}", "intent没有传入" + group + "参数,请传入!");
                    }
                }
                ValueUtils.putObjValue(data, key, val);
            }
        }
    }

    /**
     * 错误请求 回调
     *
     * @param callbackMsg
     */
    public void errorData(CallBackMsg callbackMsg) {
        if (mOverallConfig != null) {
            CallBackMsg result = mOverallConfig.onBeforeRequestError(callbackMsg);
            if (result != null) {
                callbackMsg = result;
            }
        }
        mHandler.put(callbackMsg).putWhat(ERROR).send();
    }

    /**
     * 成功回調
     *
     * @param url
     * @param id
     * @param msg
     * @param data
     * @param result 没有进行处理的值
     */
    public void successData(String url,int id, String msg, Object data, Object result) {
        if (mOverallConfig != null) {
            Object resultSet = mOverallConfig.onAfterResponse(url, id, msg, data, result);
            if (resultSet != null) {
                data = resultSet;
            }
        }
        mHandler.put(new CallBackMsg(id, url, msg, data)).putWhat(SUCCESS).send();
    }

    @Override
    public void onHandleMessage(Message msg) {
        int what = msg.what;
        if (SUCCESS == what) {
            Object obj = msg.obj;
            if ((obj != null) && obj instanceof CallBackMsg){
                CallBackMsg callbackMsg = (CallBackMsg) obj;
                onSuccess(callbackMsg.getUrl(), callbackMsg.getId(), callbackMsg.getMsg(), (T) callbackMsg.getData());
            }
        } else if (ERROR == what) {
            Object obj = msg.obj;
            if ((obj != null) && obj instanceof CallBackMsg){
                CallBackMsg callbackMsg = (CallBackMsg) obj;
                onError(callbackMsg.getUrl(), callbackMsg.getId() , callbackMsg.getErrorCode(), callbackMsg.getMsg(), callbackMsg.getData());
            }
        }
    }

    /**
     * 请求成功 回调
     *
     * @param url
     * @param id
     * @param msg
     * @param data
     */
    public void onSuccess(String url, int id, String msg, T data) {
        if (mOverallConfig != null) {
            mOverallConfig.onSuccess(url, id, msg, data);
        }
        if (onHttpListener != null) {
            onHttpListener.onSuccess(url, id, msg, data);
        }
    }

    /**
     * 请求失败 回调
     *
     * @param url
     * @param id
     * @param code
     * @param msg
     * @param data
     */
    public void onError(String url, int id, Object code, String msg, Object data) {
        if (mOverallConfig != null) {
            mOverallConfig.onError(url, id, code, msg, data);
        }
        if (onHttpListener != null) {
            onHttpListener.onError(url, id, code, msg, data);
        }
    }

    @Override
    public void inProgress(float progress, long total, int id, String url) {
        if (mOverallConfig != null) {
            mOverallConfig.inProgress(progress, total, id, url);
        }
        if (onHttpListener != null) {
            onHttpListener.inProgress(progress, total, id, url);
        }
    }

    public CommonCallback setMsgKey(String msgKey) {
        this.msgKey = msgKey;
        return this;
    }

    public CommonCallback setOnHttpListener(OnHttpListener onHttpListener) {
        this.onHttpListener = onHttpListener;
        return this;
    }

    public CommonCallback setReplaceParam(Map<String, Object> replaceParam) {
        this.replaceParam = replaceParam;
        return this;
    }

    public CommonCallback setResultClass(Class resultClass) {
        this.resultClass = resultClass;
        return this;
    }

    public Class getResponseClass() {
        return responseClass;
    }

    public CommonCallback setResponseClass(Class responseClass) {
        this.responseClass = responseClass;
        return this;
    }

    public ResponseConfigMsg getRespConfigMsg() {
        return respConfigMsg;
    }

    public CommonCallback setRespConfigMsg(ResponseConfigMsg respConfigMsg) {
        this.respConfigMsg = respConfigMsg;
        return this;
    }

}

